﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Principal;
using System.Web.SessionState;
using System.Web.Security;
using System.Text;

namespace Warehouse.Web.AppCode
{
    public class CustomPrincipal : IPrincipal
    {
        private IIdentity mIdentity;
        private string[] mRoles = null;

        public CustomPrincipal(IIdentity identity)
        {
            mIdentity = identity;
        }

        #region IPrincipal 成员

        public IIdentity Identity
        {
            get { return mIdentity; }
        }

        public bool IsInRole(string role)
        {
            return false;
        }

        #endregion
    }

    public class CustomAuthorizeModule : IHttpModule
    {
        #region IHttpModule 成员

        public void Dispose()
        {
        }

        public void Init(HttpApplication context)
        {
            context.PostAuthenticateRequest += new EventHandler(context_PostAuthenticateRequest);
        }

        void context_PostAuthenticateRequest(object sender, EventArgs e)
        {
            HttpApplication context = sender as HttpApplication;
            if (context.User.Identity is FormsIdentity)
            {
                context.Context.User = new CustomPrincipal(new CustomIdentity(context.User.Identity.Name, ((FormsIdentity)context.User.Identity).Ticket));
            }
            else
            {
                context.Context.User = new CustomPrincipal(context.User.Identity);
            }
        }

        #endregion
    }

    public class CustomIdentity : GenericIdentity
    {
        public FormsAuthenticationTicket Ticket { get; private set; }

        public CustomIdentity(string name, FormsAuthenticationTicket ticket)
            : base(name)
        {
            if (ticket != null)
            {
                this.UserInfo = SimpleUserInfo.ExtrackFromUserData(ticket.UserData);
            }
        }

        public SimpleUserInfo UserInfo { get; private set; }
    }

    public class SimpleUserInfo
    {
        public string UserName { get; set; }

        protected Dictionary<string, string> GetUserData()
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            dic.Add("UserName", this.UserName);
            return dic;
        }

        protected virtual void SetUserData(Dictionary<string, string> dictionary)
        {
            if (dictionary.ContainsKey("UserName"))
            {
                this.UserName = dictionary["UserName"];
            }
        }

        public static SimpleUserInfo ExtrackFromUserData(string userdata)
        {
            if (string.IsNullOrEmpty(userdata))
            {
                return null;
            }
            else
            {
                string[] pairs = userdata.Split(new char[] { '&' });
                Dictionary<string, string> dictionary = new Dictionary<string, string>();
                foreach (var str in pairs)
                {
                    string[] pair = str.Split(new char[] { '=' });
                    if (pair.Length == 2)
                    {
                        dictionary.Add(pair[0], pair[1]);
                    }
                }
                SimpleUserInfo userinfo = new SimpleUserInfo();
                userinfo.SetUserData(dictionary);
                return userinfo;
            }
        }

        public static string GetUserInfoData(SimpleUserInfo user)
        {
            if (user == null)
            {
                return null;
            }
            var dic = user.GetUserData();
            List<string> arr = new List<string>();
            foreach (var k in dic.Keys)
            {
                arr.Add(string.Format("{0}={1}", k, dic[k]));
            }
            return string.Join("&", arr.ToArray());
        }
    }

    public sealed class CustomAuthentication
    {
        static int _timeout = 5;
        public static int TIMEOUT
        {
            get { return _timeout; }
            set { _timeout = value; }
        }

        public static string DefaultUrl
        {
            get { return FormsAuthentication.DefaultUrl; }
        }

        public static string LoginUrl
        {
            get { return FormsAuthentication.LoginUrl; }
        }

        public static bool Authenticate(string name, string password, out bool reachFailedPasswordAttemptMaxCount,out int userId)
        {
            userId = Warehouse.DataAccess.User.Login(name, password);
            bool validatesucceed = false;
            if (userId != -1)
            {
                validatesucceed = true;
            }
            reachFailedPasswordAttemptMaxCount = false;
            if (validatesucceed)
            {
                if (!reachFailedPasswordAttemptMaxCount)
                {
                    SetAuthCookie(name, new SimpleUserInfo()
                    {
                        UserName = name
                    }, false);
                    return true;
                }
            }
            return false;
        }

        public static void SetAuthCookie(string userName, SimpleUserInfo userInfo, bool createPersistentCookie)
        {
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
                           userName,
                           DateTime.Now,
                           DateTime.Now.AddMinutes(_timeout),
                           createPersistentCookie,
                           SimpleUserInfo.GetUserInfoData(userInfo),
                           FormsAuthentication.FormsCookiePath);

            // Encrypt the ticket.
            string encTicket = FormsAuthentication.Encrypt(ticket);
            // Create the cookie.
            HttpContext.Current.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket) { Path = FormsAuthentication.FormsCookiePath });
        }

        public static void SignOut()
        {
            FormsAuthentication.SignOut();
            if (HttpContext.Current.User.Identity is CustomIdentity)
            {
                FormsAuthentication.RenewTicketIfOld(((CustomIdentity)HttpContext.Current.User.Identity).Ticket);
            }
        }

        public static void RedirectToLoginPage()
        {
            HttpContext.Current.Response.Redirect(LoginUrl + "?ReturnUrl=" + HttpUtility.UrlEncode(HttpContext.Current.Request.Url.ToString()));
        }
    }
}
